﻿using System;
using System.Windows.Media;

namespace Telerik.Windows.Documents.Utilities
{
    internal static class AlgebraExtensionsFixes
    {
        public static Matrix MultiplyBy(this Matrix m1, Matrix m2)
        {
            return new Matrix(
                (m1.M11 * m2.M11) + (m1.M12 * m2.M21), (m1.M11 * m2.M12) + (m1.M12 * m2.M22),
                (m1.M21 * m2.M11) + (m1.M22 * m2.M21), (m1.M21 * m2.M12) + (m1.M22 * m2.M22),
                (m1.OffsetX * m2.M11) + (m1.OffsetY * m2.M21) + m2.OffsetX, (m1.OffsetX * m2.M12) + (m1.OffsetY * m2.M22) + m2.OffsetY);
        }

        public static Matrix TranslateMatrix(this Matrix m, double deltaX, double deltaY)
        {
            return m.MultiplyBy(new Matrix(1, 0, 0, 1, deltaX, deltaY));
        }

        public static Matrix ScaleMatrix(this Matrix m, double scaleX, double scaleY)
        {
            return m.ScaleMatrixAt(scaleX, scaleY, 0, 0);
        }

        public static Matrix ScaleMatrixAt(this Matrix m, double scaleX, double scaleY, double centerX, double centerY)
        {
            return m.MultiplyBy(new Matrix(scaleX, 0, 0, scaleY, 0, 0).GetTransformationAt(centerX, centerY));
        }

        public static Matrix RotateMatrix(this Matrix m, double angleInDegrees)
        {
            return m.RotateMatrixAt(angleInDegrees, 0, 0);
        }

        public static Matrix RotateMatrixAt(this Matrix m, double angleInDegrees, double centerX, double centerY)
        {
            double radians = angleInDegrees * Math.PI / 180;
            double sin = Math.Sin(radians);
            double cos = Math.Cos(radians);

            return m.MultiplyBy(new Matrix(cos, sin, -sin, cos, 0, 0).GetTransformationAt(centerX, centerY));
        }

        public static Matrix InverseMatrix(this Matrix m)
        {
            ////just basic algebra
            var det = (m.M11 * m.M22) - (m.M12 * m.M21);
            var det1 = 1 / det;
            return new Matrix(m.M22 * det1, -m.M12 * det1, -m.M21 * det1, m.M11 * det1, ((m.M21 * m.OffsetY) - (m.OffsetX * m.M22)) * det1, ((m.OffsetX * m.M12) - (m.M11 * m.OffsetY)) * det1);
        }

        private static Matrix GetTransformationAt(this Matrix zeroCenteredTransform, double centerX, double centerY)
        {
            double offsetX = zeroCenteredTransform.OffsetX + (1 - zeroCenteredTransform.M11) * centerX - zeroCenteredTransform.M21 * centerY;
            double offsetY = zeroCenteredTransform.OffsetY + (1 - zeroCenteredTransform.M22) * centerY - zeroCenteredTransform.M12 * centerX;

            return new Matrix(zeroCenteredTransform.M11, zeroCenteredTransform.M12, zeroCenteredTransform.M21, zeroCenteredTransform.M22, offsetX, offsetY);
        }
    }
}
